package com.example.docmanagement.service;

import com.example.docmanagement.dto.request.PermissionCreateRequest;
import com.example.docmanagement.dto.request.PermissionQueryRequest;
import com.example.docmanagement.dto.request.PermissionUpdateRequest;
import com.example.docmanagement.dto.response.PageResponse;
import com.example.docmanagement.dto.response.PermissionResponse;
import com.example.docmanagement.dto.response.PermissionTreeResponse;
import com.example.docmanagement.entity.Permission;
import com.example.docmanagement.exception.DuplicateResourceException;
import com.example.docmanagement.exception.ResourceNotFoundException;
import com.example.docmanagement.repository.PermissionRepository;
import jakarta.persistence.criteria.Predicate;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 管理后台 - 权限管理服务
 */
@Service
@RequiredArgsConstructor
public class PermissionAdminService {

    private final PermissionRepository permissionRepository;

    /**
     * 分页查询权限
     */
    @Transactional(readOnly = true)
    public PageResponse<PermissionResponse> searchPermissions(PermissionQueryRequest request) {
        Pageable pageable = buildPageable(request);
        Specification<Permission> specification = buildSpecification(request);
        Page<Permission> page = permissionRepository.findAll(specification, pageable);

        List<PermissionResponse> data = page.getContent().stream()
                .map(this::toResponse)
                .collect(Collectors.toList());

        return PageResponse.<PermissionResponse>builder()
                .data(data)
                .page(request.getPage())
                .pageSize(request.getPageSize())
                .total(page.getTotalElements())
                .totalPages(page.getTotalPages())
                .hasNext(page.hasNext())
                .hasPrevious(page.hasPrevious())
                .build();
    }

    /**
     * 获取权限详情
     */
    @Transactional(readOnly = true)
    public PermissionResponse getPermission(Long id) {
        Permission permission = permissionRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("权限不存在"));
        return toResponse(permission);
    }

    /**
     * 创建权限
     */
    @Transactional
    public PermissionResponse createPermission(PermissionCreateRequest request) {
        if (permissionRepository.existsByName(request.getName())) {
            throw new DuplicateResourceException("权限标识已存在", request.getName());
        }

        Permission permission = Permission.builder()
                .name(request.getName())
                .displayName(request.getDisplayName())
                .description(request.getDescription())
                .resource(request.getResource())
                .action(request.getAction())
                .category(request.getCategory())
                .sortOrder(Optional.ofNullable(request.getSortOrder()).orElse(0))
                .build();

        permission = permissionRepository.save(permission);
        return toResponse(permission);
    }

    /**
     * 更新权限
     */
    @Transactional
    public PermissionResponse updatePermission(Long id, PermissionUpdateRequest request) {
        Permission permission = permissionRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("权限不存在"));

        if (request.getDisplayName() != null) {
            permission.setDisplayName(request.getDisplayName());
        }
        if (request.getDescription() != null) {
            permission.setDescription(request.getDescription());
        }
        if (request.getResource() != null) {
            permission.setResource(request.getResource());
        }
        if (request.getAction() != null) {
            permission.setAction(request.getAction());
        }
        if (request.getCategory() != null) {
            permission.setCategory(request.getCategory());
        }
        if (request.getSortOrder() != null) {
            permission.setSortOrder(request.getSortOrder());
        }

        permission = permissionRepository.save(permission);
        return toResponse(permission);
    }

    /**
     * 删除权限
     */
    @Transactional
    public void deletePermission(Long id) {
        Permission permission = permissionRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("权限不存在"));
        permissionRepository.delete(permission);
    }

    /**
     * 以模块为维度返回权限树
     */
    @Transactional(readOnly = true)
    public List<PermissionTreeResponse> getPermissionTree() {
        List<Permission> permissions = permissionRepository.findAll(Sort.by(Sort.Direction.ASC, "resource", "sortOrder", "name"));
        Map<String, List<Permission>> grouped = permissions.stream()
                .collect(Collectors.groupingBy(permission -> Optional.ofNullable(permission.getResource()).orElse("default"), LinkedHashMap::new, Collectors.toList()));

        return grouped.entrySet().stream()
                .map(entry -> PermissionTreeResponse.builder()
                        .group(entry.getKey())
                        .permissions(entry.getValue().stream()
                                .map(this::toResponse)
                                .collect(Collectors.toList()))
                        .build())
                .collect(Collectors.toList());
    }

    // ==================== 私有工具 ====================

    private Specification<Permission> buildSpecification(PermissionQueryRequest request) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (request.getKeyword() != null && !request.getKeyword().isEmpty()) {
                String keyword = "%" + request.getKeyword().toLowerCase(Locale.ROOT) + "%";
                Predicate namePredicate = cb.like(cb.lower(root.get("name")), keyword);
                Predicate displayNamePredicate = cb.like(cb.lower(root.get("displayName")), keyword);
                Predicate descriptionPredicate = cb.like(cb.lower(root.get("description")), keyword);
                predicates.add(cb.or(namePredicate, displayNamePredicate, descriptionPredicate));
            }

            if (request.getResource() != null && !request.getResource().isEmpty()) {
                predicates.add(cb.equal(root.get("resource"), request.getResource()));
            }

            if (request.getAction() != null && !request.getAction().isEmpty()) {
                predicates.add(cb.equal(root.get("action"), request.getAction()));
            }

            if (request.getCategory() != null && !request.getCategory().isEmpty()) {
                predicates.add(cb.equal(root.get("category"), request.getCategory()));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }

    private Pageable buildPageable(PermissionQueryRequest request) {
        int page = Math.max(0, request.getPage() - 1);
        int size = Math.min(Math.max(request.getPageSize(), 1), 200);
        Sort.Direction direction = "desc".equalsIgnoreCase(request.getSortOrder()) ? Sort.Direction.DESC : Sort.Direction.ASC;
        String sortProperty;
        switch (Optional.ofNullable(request.getSortBy()).orElse("").toLowerCase(Locale.ROOT)) {
            case "createdat":
                sortProperty = "createdAt";
                break;
            case "name":
                sortProperty = "name";
                break;
            default:
                sortProperty = "sortOrder";
        }
        Sort sort = Sort.by(direction, sortProperty);
        if (!"createdAt".equals(sortProperty)) {
            sort = sort.and(Sort.by(Sort.Direction.DESC, "createdAt"));
        }
        return PageRequest.of(page, size, sort);
    }

    private PermissionResponse toResponse(Permission permission) {
        return PermissionResponse.builder()
                .id(permission.getId())
                .name(permission.getName())
                .displayName(permission.getDisplayName())
                .description(permission.getDescription())
                .resource(permission.getResource())
                .action(permission.getAction())
                .category(permission.getCategory())
                .sortOrder(permission.getSortOrder())
                .createdAt(permission.getCreatedAt())
                .build();
    }
}


